﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
using System.Text;
using middleware.utiles;
using System.Data.Entity;
using middleware.dominio.persistencia.exception;

namespace middleware.dominio.persistencia
{
    public sealed class MiddlewarePersistencia : IMiddlewarePersistencia
    {
        private static readonly MiddlewarePersistencia instance = new MiddlewarePersistencia();

        public static MiddlewarePersistencia getInstance()
        {
            return instance;
        }

        public bool CrearBaseDatosSiNoExiste()
        {            
            bool aRetornar = false;
            using (MiddlewareDBContexto contexto = new MiddlewareDBContexto())
            {
                try
                {
                    //contexto.Database.Delete();
                    //Creo la tabla si no existe
                    if (contexto.Database.Exists())
                        aRetornar = true;
                    else
                        if (contexto.Database.CreateIfNotExists())
                        { //Si cree la base correctamente agrego el usuario admin por defecto
                            this.PersistirUsuario(new Usuario
                            {
                                nombre = "system",
                                usuario = "system",
                                contrasena = "system",
                                grupo = "Administrador"
                            });
                            this.PersistirUsuario(new Usuario
                            {
                                nombre = "admin",
                                usuario = "admin",
                                contrasena = "admin",
                                grupo = "Administrador"
                            });
                            this.AgregarParametroSitema(new ParametroSistema
                                {
                                    tiempoLectura = 0
                                });
                            aRetornar = true;
                        }
                }
                catch (Exception e)
                {
                    aRetornar = false;
                    throw new PersistenceException(e.Message,e);
                }
            }
            return aRetornar;
        }

        public Usuario ObtenerUsuarioPersistido(string usuario, string contrasena)
        {
            Usuario aRetornar = null;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    // METODO POR CONSULTA
                    // Armo la consulta
                    var query = from u in db.Usuarios
                                where u.usuario == usuario && u.contrasena == contrasena
                                select u;

                    if (query.Count<Usuario>() > 0)
                    {                        
                        aRetornar = (Usuario)query.First<Usuario>();                        
                    }
                    else
                    {
                        aRetornar = null;
                    }

                }
                catch (Exception e)
                {
                    aRetornar = null;
                    throw new ConsultarPersisteciaException(e.Message, e);

                }
            }
            return aRetornar;
        }

        public List<BandejaEntrada> ObtenerPersistenciaBandejasEntrada()
        {
            List<BandejaEntrada> aRetornar = new List<BandejaEntrada>();
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    // METODO POR CONSULTA
                    // Armo la consulta
                    var query = from be in db.bandejasEntrada
                                orderby be.nombre
                                select be;
                    foreach (var cursor in query)
                    {
                     
                        aRetornar.Add(cursor);
                    }

                }
                catch (Exception e)
                {
                    aRetornar = null;
                    throw new ConsultarPersisteciaException(e.Message, e);
                }
            }
            return aRetornar;
        }

        public BandejaEntrada PersistirBandejaEntrada(BandejaEntrada aPersisitir)
        {
            BandejaEntrada result = null;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    //aPersisitir.BandejaID = db.bandejasEntrada.Count() + 1;
                    db.bandejasEntrada.Add(aPersisitir);
                    db.SaveChanges();
                    result = aPersisitir;
                }
                catch (Exception e)
                {
                    result = null;
                    throw new AgregarPersisteciaException(e.Message, e);
                }
            }
            return result;
        }

        public List<BandejaSalida> ObtenerPersistenciaBandejasSalida()
        {
            List<BandejaSalida> aRetornar = new List<BandejaSalida>();
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    // METODO POR CONSULTA
                    // Armo la consulta
                    var query = from bs in db.bandejasSalida
                                orderby bs.nombre
                                select bs;
                    foreach (var cursor in query)
                    {
                        aRetornar.Add(cursor);
                    }

                }
                catch (Exception e)
                {
                    aRetornar = null;
                    throw new ConsultarPersisteciaException(e.Message, e);
                }
            }
            return aRetornar;
        }

        public BandejaSalida PersistirBandejaSalida(BandejaSalida aPersisitir)
        {
            BandejaSalida result = null;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    //aPersisitir.BandejaId = db.bandejasSalida.Count() + 1;
                    db.bandejasSalida.Add(aPersisitir);
                    db.SaveChanges();
                    result = aPersisitir;
                }
                catch (Exception e)
                {
                    result = null;
                    throw new AgregarPersisteciaException(e.Message, e);
                }
            }
            return result;
        }

        public BandejaEntrada ObtenerBandejaEntradaPersistida(string nombreBandeja)
        {
            BandejaEntrada aRetornar = new BandejaEntrada();
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    // METODO POR CONSULTA
                    // Armo la consulta
                    var query = from be in db.bandejasEntrada
                                where be.nombre == nombreBandeja
                                select be;

                    if (query.Count<BandejaEntrada>() > 0)
                    {
                        aRetornar = (BandejaEntrada)query.First<BandejaEntrada>();
                    }
                    else
                    {
                        aRetornar = null;
                    }

                }
                catch (Exception e)
                {
                    aRetornar = null;
                    throw new ConsultarPersisteciaException(e.Message, e);

                }
            }
            return aRetornar;
        }

        public BandejaSalida ObtenerBandejaSalidaPersistida(string nombreBandeja)
        {
            BandejaSalida aRetornar = new BandejaSalida();
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    // METODO POR CONSULTA
                    // Armo la consulta
                    var query = from bs in db.bandejasSalida
                                where bs.nombre == nombreBandeja
                                select bs;
                    if (query.Count<BandejaSalida>() > 0)
                    {
                        aRetornar = (BandejaSalida)query.First<BandejaSalida>();
                    }
                    else
                    {
                        aRetornar = null;
                    }
                }
                catch (Exception e)
                {
                    aRetornar = null;
                    throw new ConsultarPersisteciaException(e.Message, e);
                }
            }
            return aRetornar;
        }

        public Boolean ModificarBandejaEntradaPersistida(BandejaEntrada bandeja, ITipoBandejaEntrada tipoBandejaEntrada, string nombre, string configuracion)
        {
            Boolean result = true;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    // METODO POR CONSULTA
                    // Armo la consulta
                    var query = from be in db.bandejasEntrada
                                where be.BandejaID == bandeja.BandejaID
                                select be;
                    BandejaEntrada bandejaEntrada = (BandejaEntrada)query.First<BandejaEntrada>();
                    if (!String.IsNullOrEmpty(nombre))
                    {
                        bandejaEntrada.nombre = nombre;
                    }
                    if (!String.IsNullOrEmpty(nombre))
                    {
                        bandejaEntrada.configuracion = configuracion;
                    }
                    if (tipoBandejaEntrada != null)
                    {
                        bandejaEntrada.tipoBandeja = tipoBandejaEntrada;
                        bandejaEntrada.nombreTipoBandeja = tipoBandejaEntrada.ToString();
                    }
                    db.SaveChanges();

                }
                catch (Exception e)
                {
                        result = false;
                        throw new ModificarPersistenciaException(e.Message, e);
                }
            }
            return result;
        }

        public Boolean ModificarBandejaSalidaPersistida(BandejaSalida bandeja, ITipoBandejaSalida tipoBandejaSalida, string nombre, string configuracion)
        {
            Boolean result = true;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    // METODO POR CONSULTA
                    // Armo la consulta
                    var query = from bs in db.bandejasSalida
                                where bs.BandejaId == bandeja.BandejaId
                                select bs;
                    BandejaSalida bandejaSalida = (BandejaSalida)query.First<BandejaSalida>();
                    if (!String.IsNullOrEmpty(nombre))
                    {
                        bandejaSalida.nombre = nombre;
                    }
                    if (!String.IsNullOrEmpty(nombre))
                    {
                        bandejaSalida.configuracion = configuracion;
                    }
                    if (tipoBandejaSalida != null)
                    {
                        bandejaSalida.tipoBandeja = tipoBandejaSalida;
                        bandejaSalida.nombreTipoBandeja = tipoBandejaSalida.ToString();
                    }
                    db.SaveChanges();
                }
                catch (Exception e)
                {
                    result = false;
                    throw new ModificarPersistenciaException(e.Message, e);
                }
            }
            return result;
        }

        public Boolean ModificarReglaPersistida(Regla regla, string nombreAtributo, string condicion, string valorAtributo, BandejaSalida bandejaSalida)
        {
            Boolean result = true;

            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    // METODO POR CONSULTA
                    // Armo la consulta
                    var query = from r in db.Reglas
                                where r.ReglaId == regla.ReglaId
                                select r;
                    Regla reglaModificada = (Regla)query.First<Regla>();
                    if (!String.IsNullOrEmpty(nombreAtributo))
                    {
                        reglaModificada.nombreAtributo = nombreAtributo;
                    }
                    if (!String.IsNullOrEmpty(condicion))
                    {
                        reglaModificada.codicion = condicion;
                    }
                    if (!String.IsNullOrEmpty(nombreAtributo))
                    {
                        reglaModificada.valorAtributo = valorAtributo;
                    }
                    if (bandejaSalida != null)
                    {
                        db.bandejasSalida.Attach(bandejaSalida);
                        reglaModificada.bandeja = bandejaSalida;
                    }
                    db.SaveChanges();

                }
                catch (Exception e)
                {
                    result = false;
                    throw new ModificarPersistenciaException(e.Message, e);
                }
            }

            return result;
        }


        public Boolean EliminarBandejaEntrada(BandejaEntrada bandeja)
        {
            Boolean result = true;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    var query = from be in db.bandejasEntrada
                                where be.nombre == bandeja.nombre
                                select be;

                    foreach (var bandejaEntrada in query)
                    {
                        db.bandejasEntrada.Remove(bandejaEntrada);
                    }
                    db.SaveChanges();
                }
                catch (Exception e)
                {
                    result = false;
                    throw new PersistenceException(e.Message, e);
                }
            }
            return result;
        }

        public Boolean EliminarBandejaSalida(BandejaSalida bandeja)
        {
            Boolean result = true;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    var query = from bs in db.bandejasSalida
                                where bs.nombre == bandeja.nombre
                                select bs;

                    foreach (var bandejaSalida in query)
                    {
                        db.bandejasSalida.Remove(bandejaSalida);
                    }
                    db.SaveChanges();
                }
                catch (Exception e)
                {
                    result = false;
                    throw new PersistenceException(e.Message, e);
                }
            }
            return result;
        }

        public Boolean EliminarRegla(Regla regla)
        {
            Boolean result = true;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    var query = from r in db.Reglas
                                where r.ReglaId == regla.ReglaId
                                select r;
                    foreach (var reglaPersistida in query)
                    {
                        db.Reglas.Remove(reglaPersistida);
                    }
                    db.SaveChanges();
                }
                catch (Exception e)
                {
                    result = false;
                    throw new PersistenceException(e.Message, e);
                }
            }
            return result;
        }

        public Boolean PersistirHistorico(Historico historico)
        {
            Boolean result = true;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    foreach (Atributo a in historico.mensaje.atributos)
                        db.Atributos.Attach(a);
                    historico.BandejaSalidaID = historico.bandejaSalida.BandejaId;
                    historico.bandejaSalida = null;                     
                    db.Mensajes.Attach(historico.mensaje);
                    db.bandejasEntrada.Attach(historico.bandejaEntrada);                    
                    db.bandejasSalida.Attach(historico.regla.bandeja);
                    db.Reglas.Attach(historico.regla);
                    db.Historicos.Add(historico);
                    db.SaveChanges();
                }
                catch (Exception e)
                {
                    result = false;
                    throw new AgregarPersisteciaException(e.Message, e);
                }
            }
            return result;
        }

        public List<Regla> ObtenerPersistenciaReglas()
        {
            List<Regla> aRetornar = new List<Regla>();
            using (var db = new MiddlewareDBContexto())
            {
                try
                {                    
                    // METODO POR CONSULTA
                    // Armo la consulta
                    var query = from r in db.Reglas.Include("bandeja")                                
                                orderby r.ReglaId
                                select r;
                    foreach (var cursor in query)
                    {                        
                        aRetornar.Add(cursor);
                    }

                }
                catch (Exception e)
                {
                    aRetornar = null;
                    throw new ConsultarPersisteciaException(e.Message, e);

                }
            }
            return aRetornar;
        }

        public Regla PersistirRegla(Regla aPersisitir)
        {
            Regla result = null;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    //aPersisitir.ReglaId = db.Reglas.Count() + 1;
                    db.bandejasSalida.Attach(aPersisitir.bandeja);
                    db.Reglas.Add(aPersisitir);
                    db.SaveChanges();
                    result = aPersisitir;
                }
                catch (Exception e)
                {
                    result = null;
                    throw new AgregarPersisteciaException(e.Message, e);
                }
            }
            return result;
        }

        public List<Historico> ObtenerHistoricoPersistido(DateTime fecha, BandejaEntrada bandejaEntrada, string nombreAtributo, string valorAtributo)
        {
            DateTime fechaNula = new DateTime();
            List<Historico> result = new List<Historico>();

            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    var query = from h in db.Historicos
                                .Include("mensaje")
                                .Include("bandejaEntrada")
                                .Include("bandejaSalida")
                                .Include("regla")
                                .Include("mensaje.atributos")
                                .Include("regla.bandeja")
                                select h;


                    if (!(fechaNula.Day == fecha.Day && fechaNula.Month == fecha.Month && fechaNula.Year == fecha.Year))
                    {
                        query = query.Where(h => h.fecha.Day == fecha.Day && h.fecha.Month == fecha.Month && h.fecha.Year == fecha.Year);
                    }

                    if (bandejaEntrada != null)
                    {
                        query = query.Where(h => h.bandejaEntrada.BandejaID == bandejaEntrada.BandejaID);
                    }

                    query.GroupBy(h => h.MensajeID);

                    if (!String.IsNullOrEmpty(nombreAtributo) && !String.IsNullOrEmpty(valorAtributo))
                    {
                        foreach (var historico in query)
                        {
                            historico.mensaje = db.Mensajes.Where(m => m.MensajeID == historico.MensajeID).Single();
                            historico.mensaje.atributos = db.Atributos.Where(a => a.MensajeId == historico.MensajeID).ToList<Atributo>();
                            var queryAtributos = from a in historico.mensaje.atributos
                                                 where a.nombre.CompareTo(nombreAtributo) == 0 && a.valor.CompareTo(valorAtributo) == 0
                                                 select a;
                            if (queryAtributos.Count() > 0)
                            {
                                result.Add(historico);
                            }
                        }
                    }
                    else
                    {
                        foreach (var historico in query)
                        {
                            result.Add(historico);
                        }
                    }
                }
                catch (Exception e)
                {
                    result = null;
                    throw new ConsultarPersisteciaException(e.Message, e);
                }
            }

            return result;
        }

        public Boolean PersistirLog(Log aPersisitir)
        {
            Boolean result = true;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    //aPersisitir.LogId = db.Logs.Count() + 1;
                    db.Usuarios.Attach(aPersisitir.usuario);
                    db.Logs.Add(aPersisitir);
                    db.SaveChanges();
                }
                catch (Exception e)
                {
                    result = false;
                    throw new AgregarPersisteciaException(e.Message, e);
                }
            }
            return result;
        }

        public List<Log> ObtenerLogs(DateTime fecha, string linea)
        {
            DateTime fechaNula = new DateTime();
            List<Log> result = new List<Log>();

            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    var query = from l in db.Logs.Include("usuario")
                                select l;


                    if (!fecha.Equals(fechaNula))
                    {
                        query = query.Where(l => l.fecha.Equals(fecha));
                    }

                    if (!String.IsNullOrEmpty(linea))
                    {
                        query = query.Where(l => l.linea.Contains(linea));
                    }

                    foreach (var log in query)
                    {
                        result.Add(log);
                    }

                }
                catch (Exception e)
                {
                    result = null;
                    throw new ConsultarPersisteciaException(e.Message, e);
                }
            }

            return result;
        }

        public Usuario PersistirUsuario(Usuario aPersisitir)
        {
            Usuario result = null;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {                   
                    db.Usuarios.Add(aPersisitir);
                    db.SaveChanges();
                    result = aPersisitir;
                }
                catch (Exception e)
                {
                    result = null;
                    throw new AgregarPersisteciaException(e.Message, e);
                }
            }
            return result;
        }

        public ParametroSistema PersistirParametroSistema(ParametroSistema aPersisitir, int tiempo)
        {
            ParametroSistema result = null;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    // METODO POR CONSULTA
                    // Armo la consulta
                    var query = from ps in db.ParametrosSistema
                                where ps.ParsisId == aPersisitir.ParsisId
                                select ps;
                    ParametroSistema parametro = (ParametroSistema)query.First<ParametroSistema>();
                    parametro.tiempoLectura = tiempo;
                    db.SaveChanges();
                    result = parametro;
                }
                catch (Exception e)
                {
                    result = null;
                    throw new AgregarPersisteciaException(e.Message, e);
                }
            }
            return result;
        }

        public ParametroSistema ObtenerParametroSistema()
        {
            ParametroSistema aRetornar = null;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    // METODO POR CONSULTA
                    // Armo la consulta
                    var query = from ps in db.ParametrosSistema
                                select ps;
                    foreach (var cursor in query)
                    {
                        aRetornar = cursor;
                        break;
                    }
                }
                catch (Exception e)
                {
                    aRetornar = null;
                    throw new ConsultarPersisteciaException(e.Message, e);
                }
            }
            return aRetornar;
        }

        private void AgregarParametroSitema(ParametroSistema parametro)
        {
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    db.ParametrosSistema.Add(parametro);
                    db.SaveChanges();
                }
                catch (Exception e)
                {
                    throw new AgregarPersisteciaException(e.Message, e);
                }
            }
        }

        public Mensaje PersistirMensaje(Mensaje aPersisitir)
        {
            Mensaje result = null;
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    db.Mensajes.Add(aPersisitir);
                    db.SaveChanges();
                    result = aPersisitir;
                }
                catch (Exception e)
                {
                    result = null;
                    throw new AgregarPersisteciaException(e.Message, e);
                }
            }
            return result;
        }


        public List<String[]> ObtenerEjecucionConsultaDinamica(string strSelect, string strWhere, string strGroupby)
        {
            List<String[]> aRetornar = new List<string[]>();
            using (var db = new MiddlewareDBContexto())
            {
                try
                {
                    // Realizo la consulta, y ejecuto la mas adecuada dados los parametros que ingresan.
                    // En caso de tener un groupby se tiene que ejecutar hacer un split y asi hallar el group key y con lo que agrupamos.
                    if (!String.IsNullOrEmpty(strWhere) && !String.IsNullOrEmpty(strGroupby))
                    {
                        string[] arrGroupby = strGroupby.Split(new char[] { '~' });
                        aRetornar = db.Historicos.Where(strWhere).GroupBy(arrGroupby[0], arrGroupby[1]).Select(strSelect).ToStringArray();
                    }
                    else if (!String.IsNullOrEmpty(strWhere))
                    {
                        aRetornar = db.Historicos.Where(strWhere).Select(strSelect).ToStringArray();
                    }
                    else if (!String.IsNullOrEmpty(strGroupby))
                    {
                        string[] arrGroupby = strGroupby.Split(new char[] { '~' });
                        aRetornar = db.Historicos.GroupBy(arrGroupby[0], arrGroupby[1]).Select(strSelect).ToStringArray();
                    }
                    else
                    {
                        aRetornar = db.Historicos.Select(strSelect).ToStringArray();
                    }
                }
                catch (ParseException e)
                {
                    aRetornar = null;
                    throw new ConsultarPersisteciaException(e.Message, e);
                }
                catch (Exception e)
                {
                    aRetornar = null;
                    throw new ConsultarPersisteciaException(e.Message, e);
                }
            }
            return aRetornar;
        }
    }
}
